package com.study.example.study.extension.easyexcel.read;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.google.common.base.Stopwatch;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * easyexcel 读数据策略工厂
 *
 * @author RenYuLiang
 */
@Log4j2
@Component
public class EasyExcelReadDataStrategyFactory {


    /**
     * 读 文件
     *
     * @param strategyEnum EasyExcelReadStrategyEnum 策略类型
     * @param fileName     文件
     */
    public void read(final EasyExcelReadStrategyEnum strategyEnum, final String fileName) {
        // 建的时候就开始计时
        Stopwatch stopwatch = Stopwatch.createStarted();
        if (Objects.isNull(strategyEnum)) {
            return;
        }
        // 这里 读不同的 sheet 不同的对象
        try (ExcelReader excelReader = EasyExcel.read(fileName).build()) {
            // 读数据
            this.readData(strategyEnum, excelReader);
        }
        // 停止计时，然后计算时长.单位为毫秒
        long elapsed = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
        log.info("读excel结束,耗时(毫秒)={}", elapsed);
        System.out.println("读excel结束,耗时(毫秒)=" + elapsed);
    }

    /**
     * 上传 文件 读
     *
     * @param strategyEnum EasyExcelReadStrategyEnum 策略类型
     * @param inputStream  InputStream 文件流
     */
    public void upload(final EasyExcelReadStrategyEnum strategyEnum, final InputStream inputStream) {
        // 建的时候就开始计时
        Stopwatch stopwatch = Stopwatch.createStarted();
        if (Objects.isNull(strategyEnum)) {
            return;
        }
        // 这里 读不同的 sheet 不同的对象
        try (ExcelReader excelReader = EasyExcel.read(inputStream).build()) {
            // 读数据
            this.readData(strategyEnum, excelReader);
        }
        // 停止计时，然后计算时长.单位为毫秒
        long elapsed = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
        log.info("读excel结束,耗时(毫秒)={}", elapsed);
        System.out.println("读excel结束,耗时(毫秒)=" + elapsed);
    }

    /**
     * 读数据
     *
     * @param strategyEnum 读数据策略
     * @param excelReader  ExcelReader
     */
    private void readData(final EasyExcelReadStrategyEnum strategyEnum, final ExcelReader excelReader) {
        // 单线程 多个 sheet 循环读数据
        List<ReadSheet> readSheetList = new ArrayList<>(strategyEnum.getSheetNum());
        ReadSheet readSheet;
        for (int i = 0; i < strategyEnum.getSheetNum(); i++) {
            readSheet = this.createReadSheet(strategyEnum, i);
            readSheetList.add(readSheet);
        }
        // 这里注意 一定要把 所有 sheet 一起传进去，不然有个问题就是 03 版的 excel 会读取多次，浪费性能
        excelReader.read(readSheetList);
    }

    /**
     * 创建 单个 sheet 读数据 可能返回空
     *
     * @param strategyEnum EasyExcelReadStrategyEnum
     * @param i            int 第几个sheet
     * @return ReadSheet
     */
    private ReadSheet createReadSheet(final EasyExcelReadStrategyEnum strategyEnum, int i) {
        if (StringUtils.isBlank(strategyEnum.getReadHandlerArray()[i])) {
            return null;
        }
        // 获取 sheet 读数据的策略
        EasyExcelReadDataStrategy<?> strategy = SpringUtil.getBean(strategyEnum.getReadHandlerArray()[i]);
        if (Objects.isNull(strategy)) {
            return null;
        }
        return EasyExcel.readSheet(i).head(strategy.getReadClass()).registerReadListener(strategy.getReadListener()).build();
    }

}
